// Copyright 2011 Jay Young. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS-IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

/**
 * @fileoverview
 *
 * Declares a record type which represents a blog post.
 */

goog.provide('rb.post.BlogPost');

goog.require('goog.date.DateTime');

goog.require('rb.Author');
goog.require('rb.utils.dates');

goog.require('relief.cache.Cloneable');



/**
 * A blog post consists of the title, content, time of creation, and its author.
 * If the post has come from the server, or has been newly created and saved to
 * the server, it will also have a unique slug, which acts as its cache key as
 * well as the key name of the server-side datastore entity.
 *
 * @param {string} title The post's title.
 * @param {string} content The post's content.
 * @param {rb.Author} author The post's author's registered display name.
 * @param {string=} created The time and date of this post's creation.  Will
 *    set created to now if omitted.
 * @param {string=} slug The post's unique slug.
 *
 * @constructor
 * @implements {relief.cache.Cloneable}
 */
rb.post.BlogPost = function(title, content, author, created, slug) {
  /**
   * If this BlogPost object was constructed from a server response that was
   * only meant to retrieve post details but not the contents, isSummary will
   * be true.  Otherwise, it will be false.
   *
   * @type {boolean}
   * @const
   */
  this.isSummary = content === '';

  /**
   * @type {string}
   * @private
   */
  this.title_ = title;

  /**
   * @type {string}
   * @private
   */
  this.content_ = content;

  /**
   * @type {rb.Author}
   * @private
   */
  this.author_ = author;

  // Safari cannot parse timestamps of the format "2011-06-26T21:23:18-04:00".
  // If doing "new Date('...');" results in NaN, do it the hard way.

  var date;
  if (created) {
    date = new Date(created);
    if (isNaN(date)) {
      date = goog.date.fromIsoString(created);
    }
    else {
      date = new goog.date.DateTime(date);
    }
  }
  else {
    date = new goog.date.DateTime(new Date());
  }

  /**
   * @type {goog.date.DateTime}
   * @private
   */
  this.created_ = date;

  /**
   * @type {string|undefined}
   * @private
   */
  this.slug_ = slug;
};


/**
 * The structure of JSON objects sent by the server representing blog post
 * data.
 *
 * @typedef {{title: string, content: string, author: rb.Author,
 *            created: string, slug: string}}
 */
rb.post.BlogPost.ServerResponse;


/**
 * Static factory method to get a new BlogPost object out of a server-returned
 * JSON object.
 *
 * @param {rb.post.BlogPost.ServerResponse} obj The parsed JSON object from the
 *    server.
 * @return {rb.post.BlogPost} A new BlogPost instance.
 */
rb.post.BlogPost.fromServerResponse = function(obj) {
  var author = obj['author'],
      postAuthor = {
        displayName: author['name'],
        userId: author['userId'],
        title: author['title']
      };

  return new rb.post.BlogPost(obj['title'], obj['content'], postAuthor,
                              obj['created'], obj['slug']);
};


/**
 * @param {string} slug The slug of the post to store in or retrieve from
 *    the cache.
 * @return {string} The cache key for the given slug.
 */
rb.post.BlogPost.getCacheKey = function(slug) {
  return 'BlogPost:' + slug;
};


/**
 * @param {string} slug The slug to store as the unique key for this BlogPost.
 */
rb.post.BlogPost.prototype.setSlug = function(slug) {
  this.slug_ = slug;
};


/**
 * @return {!rb.post.BlogPost} A clone of this blog post.
 * @override
 */
rb.post.BlogPost.prototype.clone = function() {
  var author = this.author_,
      newAuthor = {
        displayName: author.displayName,
        userId: author.userId,
        title: author.title
      };

  return new rb.post.BlogPost(this.title_, this.content_, newAuthor,
                              rb.utils.dates.toIsoString(this.created_),
                              this.slug_);
};


/**
 * @return {string} The post's title.
 */
rb.post.BlogPost.prototype.getTitle = function() {
  return this.title_;
};


/**
 * @return {string} A shortened version of the title.
 */
rb.post.BlogPost.prototype.getShortTitle = function() {
  var title = this.title_;
  return title.length > 30 ? title.slice(0, 20) + '...' : title;
};


/**
 * @return {string} The post's content.
 */
rb.post.BlogPost.prototype.getContent = function() {
  return this.content_;
};


/**
 * @return {rb.Author} The post's author.
 */
rb.post.BlogPost.prototype.getAuthor = function() {
  var author = this.author_;
  return {
    displayName: author.displayName,
    userId: author.userId,
    title: author.title
  };
};


/**
 * @return {string} The ISO-formatted creation time.
 */
rb.post.BlogPost.prototype.getCreatedAsIso = function() {
  return rb.utils.dates.toIsoString(this.created_);
};


/**
 * @return {string} A display-formatted time stamp.
 */
rb.post.BlogPost.prototype.getCreatedForDisplay = function() {
  return new Date(this.created_.valueOf()).toLocaleString();
};


/**
 * @return {string|undefined} The post's unique slug.
 */
rb.post.BlogPost.prototype.getSlug = function() {
  return this.slug_;
};


/**
 * @return {string|undefined} The cache key for this post or undefined if the
 *    post's slug hasn't been set.
 */
rb.post.BlogPost.prototype.getCacheKey = function() {
  var slug = this.slug_;
  if (slug) {
    return rb.post.BlogPost.getCacheKey(slug);
  }
  else {
    return undefined;
  }
};


/**
 * @type {Array.<string>}
 */
rb.post.BlogPost.Month = [
  'January ',
  'February ',
  'March ',
  'April ',
  'May ',
  'June ',
  'July ',
  'August ',
  'September ',
  'October ',
  'November ',
  'December '
];


/**
 * @return {string} A string including the month and year of the blog post,
 *    formatted as "June 2011".
 */
rb.post.BlogPost.prototype.getMonthYear = function() {
  var date = this.created_,
      monthYear = rb.post.BlogPost.Month[date.getMonth()] + date.getFullYear();
  return monthYear;
};
